package com.example.uploadminio.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.Utilities;
import java.io.File;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class FileWatcher implements Runnable {
    private static final Logger log = LoggerFactory.getLogger(FileWatcher.class);
    private static final long PART_SIZE = 5 * 1024 * 1024; // 5MB

    private final Path rootPath;
    private final MinioUploader uploader;
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    private final JTextArea logArea;
    private final JTextArea progressArea;
    private final Set<Path> uploadedFiles = new HashSet<>();
    private volatile boolean running = true;
    private ScheduledExecutorService scheduler;
    // 在类的开头加一个 Set，避免重复日志
    private final Set<String> uploadedLogs = Collections.synchronizedSet(new HashSet<>());
    // 保存每个文件的进度，线程安全
    private final Map<String, String> progressMap = new java.util.concurrent.ConcurrentHashMap<>();

    // 新增：跟踪当前正在上传任务数
    private final AtomicInteger uploadingCount = new AtomicInteger(0);

    public FileWatcher(Path rootPath, MinioUploader uploader, JTextArea logArea, JTextArea progressArea) {
        this.rootPath = rootPath;
        this.uploader = uploader;
        this.logArea = logArea;
        this.progressArea = progressArea;
    }

    private void logInfo(String msg) {
        log.info(msg);
        if (logArea != null) {
            SwingUtilities.invokeLater(() -> {
                logArea.append("[INFO] " + msg + "\n");
                logArea.setCaretPosition(logArea.getDocument().getLength());
            });
        }
    }

    private void logError(String msg, Throwable e) {
        log.error(msg, e);
        if (logArea != null) {
            SwingUtilities.invokeLater(() -> {
                logArea.append("[ERROR] " + msg + " " + e.getMessage() + "\n");
                logArea.setCaretPosition(logArea.getDocument().getLength());
            });
        }
    }

    public void stop() {
        running = false;
        executor.shutdownNow();
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdownNow();
        }
    }

    @Override
    public void run() {
        try {
            if (!Files.exists(rootPath)) {
                Files.createDirectories(rootPath);
            }
            uploader.ensureBucket();

            long interval = uploader.getProperties().getScanInterval(); // 分钟
            scheduler = Executors.newSingleThreadScheduledExecutor();

            scheduler.scheduleAtFixedRate(() -> {
                if (!running) return;

                // 新增：如果有任务正在上传，跳过本次扫描
                if (uploadingCount.get() > 0) {
                    logInfo("有上传任务正在进行，本次扫描跳过");
                    return;
                }
                try {
                    logInfo("开始扫描目录: " + rootPath + " | 时间: " +
                            java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    scanAndUpload(rootPath);
                } catch (Exception e) {
                    logError("扫描目录失败", e);
                }
            }, 0, interval, TimeUnit.MINUTES);

            logInfo("开始定时扫描目录: " + rootPath + " 间隔: " + interval + " 分钟");

            while (running) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    logInfo("FileWatcher 线程被中断，准备退出...");
                    Thread.currentThread().interrupt();
                    break;
                }
            }

        } catch (Exception e) {
            logError("Watcher启动失败", e);
        } finally {
            logInfo("FileWatcher 已停止");
        }
    }

    private void scanAndUpload(Path dir) throws Exception {
        Files.walk(dir)
                .filter(Files::isRegularFile)
                .forEach(this::submitUpload);
    }

    // 定义一个 Map 保存每个文件对应的 Document 行起始位置
    private final Map<String, Integer> progressLineMap = new HashMap<>();

    private void submitUpload(Path filePath) {
        executor.submit(() -> {
            uploadingCount.incrementAndGet(); // 上传任务开始
            try {
                if (!Files.exists(filePath)) {
                    logInfo("文件不存在: " + filePath);
                    return;
                }

                Path relativePath = rootPath.toAbsolutePath().normalize()
                        .relativize(filePath.toAbsolutePath().normalize());
                String objectName = relativePath.toString().replace(File.separatorChar, '/');

                String prefix = uploader.getProperties().getBucketPrefix();
                if (StringUtils.hasText(prefix)) {
                    objectName = prefix + "/" + objectName;
                }

                boolean exists = false;
                try {
                    exists = uploader.objectExists(objectName);
                } catch (Exception e) {
                    logError("检查对象是否存在失败: " + objectName, e);
                }

                if (!exists) {
                    long start = System.currentTimeMillis();
                    logInfo("文件上传开始: " + objectName);

                    boolean success;
                    if (filePath.toFile().length() > MinioUploader.PART_SIZE) { // 大文件
                        final String objectNameFinal = objectName;
                        success = uploader.uploadLargeFileWithProgress(filePath.toFile(), objectNameFinal, (uploaded, total) -> {
                            double percent = (uploaded * 100.0 / total);

                            // 日志只打印一次
                            if (!uploadedLogs.contains(objectNameFinal)) {
                                uploadedLogs.add(objectNameFinal);

                                SwingUtilities.invokeLater(() -> {
                                    try {
                                        Document doc = logArea.getDocument();
                                        String logText = String.format("[INFO] %s 上传中...", objectNameFinal);
                                        doc.insertString(doc.getLength(), logText + "\n", null);
                                        logArea.setCaretPosition(doc.getLength());
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                });
                            }
                            // 更新进度 Map
                            progressMap.put(objectNameFinal, String.format("[PROGRESS] %s %.2f%%", objectNameFinal, percent));

                            // 刷新整个进度区
                            refreshProgressArea();

                            // 上传完成后删除该任务进度
                            if (uploaded == total) {
                                progressMap.remove(objectNameFinal);
                                refreshProgressArea();
                            }

                        });

                    } else { // 小文件
                        success = uploader.uploadWithRetry(filePath.toFile(), objectName);
                    }

                    long end = System.currentTimeMillis();

                    if (success) {
                        synchronized (uploadedFiles) {
                            uploadedFiles.add(filePath);
                        }
                        logInfo("文件上传成功: " + objectName + ", 耗时 " + (end - start) / 1000.0 + " 秒");
                    } else {
                        logInfo("文件上传失败: " + objectName + ", 耗时 " + (end - start) / 1000.0 + " 秒");
                    }
                }
            } catch (Exception e) {
                logError("上传失败: " + filePath, e);
            } finally {
                uploadingCount.decrementAndGet(); // 上传任务结束
            }
        });
    }

    /**
     * 更新 progressArea，显示所有文件的进度
     */
    private void refreshProgressArea() {
        SwingUtilities.invokeLater(() -> {
            try {
                StringBuilder sb = new StringBuilder();

                progressMap.forEach((fullPath, text) -> {
                    // 取最后两级路径显示
                    Path path = Paths.get(fullPath);
                    String displayPath;
                    Path fileName = path.getFileName();
                    Path parent = path.getParent();
                    if (parent != null) {
                        displayPath = parent.getFileName() + "/" + fileName;
                    } else {
                        displayPath = fileName.toString();
                    }

                    // 从 text 解析百分比
                    double percent = 0.0;
                    if (text.contains("%")) {
                        try {
                            String num = text.substring(text.lastIndexOf(' ') + 1).replace("%", "");
                            percent = Double.parseDouble(num);
                        } catch (Exception ignored) {}
                    }

                    // 生成进度条
                    int barLength = 20;
                    int done = (int)(percent / 100 * barLength);
                    String bar = "[" + "=".repeat(done) + " ".repeat(barLength - done) + "]";

                    // 拼接最终显示行，加上 [PROGRESS] 前缀
                    sb.append(String.format("[PROGRESS] %-30s %s %6.2f%%\n", displayPath, bar, percent));
                });

                progressArea.setText(sb.toString());
                progressArea.setCaretPosition(progressArea.getDocument().getLength());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }


}
